/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "fast_math.h"

#include <math.h>
#include <stdint.h>

#include "checks.h"

namespace webrtc {

    namespace {

        float FastLog2f(float in) {
            RTC_DCHECK_GT(in, .0f);
            // Read and interpret float as uint32_t and then cast to float.
            // This is done to extract the exponent (bits 30 - 23).
            // "Right shift" of the exponent is then performed by multiplying
            // with the constant (1/2^23). Finally, we subtract a constant to
            // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
            union {
                float dummy;
                uint32_t a;
            } x = {in};
            float out = x.a;
            out *= 1.1920929e-7f;  // 1/2^23
            out -= 126.942695f;    // Remove bias.
            return out;
        }

    }  // namespace

    float SqrtFastApproximation(float f) {
        // TODO(peah): Add fast approximate implementation.
        return sqrtf(f);
    }

    float Pow2Approximation(float p) {
        // TODO(peah): Add fast approximate implementation.
        return powf(2.f, p);
    }

    float PowApproximation(float x, float p) {
        return Pow2Approximation(p * FastLog2f(x));
    }

    float LogApproximation(float x) {
        constexpr float kLogOf2 = 0.69314718056f;
        return FastLog2f(x) * kLogOf2;
    }

    void LogApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
        for (size_t k = 0; k < x.size(); ++k) {
            y[k] = LogApproximation(x[k]);
        }
    }

    float ExpApproximation(float x) {
        constexpr float kLog10Ofe = 0.4342944819f;
        return PowApproximation(10.f, x * kLog10Ofe);
    }

    void ExpApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
        for (size_t k = 0; k < x.size(); ++k) {
            y[k] = ExpApproximation(x[k]);
        }
    }

    void ExpApproximationSignFlip(rtc::ArrayView<const float> x,
                                  rtc::ArrayView<float> y) {
        for (size_t k = 0; k < x.size(); ++k) {
            y[k] = ExpApproximation(-x[k]);
        }
    }

}  // namespace webrtc
